<template>
    <div class="content" ref="content" id="content">
        <!-- <Loading v-if="!loadingPercentage.completed" size="220" color="#03b2c9" :text="loadingPercentage.percentage"
            dot-count="6" /> -->
        <div ref="container" class="three-container"
            :style="{ width: `calc(100vw - ${containerOffsetLeft})`, height: `calc(100vh - ${containerOffsetTop})` }">
        </div>
        <BottomContent v-if="loadingPercentage.completed" :itemList="[]">
            <template #default>
                <div class="button-list" v-if="isHideSheBei">
                    <div class="button" @click="showModuleQiang(true)">
                        <img src="@/assets/three/button-background.svg" alt="">
                        <div class="label">
                            关闭设备
                        </div>
                    </div>
                </div>
                <div class="button-list">
                    <div class="button" @click="showModuleQiang(false)">
                        <img src="@/assets/three/button-background.svg" alt="">
                        <div class="label">
                            显示设备
                        </div>
                    </div>
                </div>
                <div class="button-list" v-if="isHideGuanDao">
                    <div class="button" @click="hideGuanDao(true)">
                        <img src="@/assets/three/button-background.svg" alt="">
                        <div class="label">
                            关闭管网
                        </div>
                    </div>
                </div>
                <div class="button-list">
                    <div class="button" @click="showGuanDaoMoudle">
                        <img src="@/assets/three/button-background.svg" alt="">
                        <div class="label">
                            显示管网
                        </div>
                    </div>
                </div>
            </template>
        </BottomContent>
    </div>
</template>

<script setup async>
import { ref, onMounted, onBeforeUnmount, defineEmits, defineProps, } from 'vue'
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass'
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader'
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass'
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
import { CSS2DRenderer, CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer"

import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js'
import { TilesRenderer } from '3d-tiles-renderer'
import { gsap } from 'gsap'
import Loading from '@/components/Loading'
import { useFullscreen } from '@vueuse/core'
import 'animate.css/animate.min.css';
import { Group, Tween, Easing } from '@tweenjs/tween.js'
import textBackground from '@/assets/three/text-bac.png';
import lineBackground from '@/assets/three/icon-sjx.svg';
import autofit from "autofit.js";

const props = defineProps({
    outlinePass: {
        type: Boolean,
        default: true
    }
})
const emit = defineEmits(['loadingFinish']);
// DOM 引用
const container = ref(null)
const containerOffsetLeft = ref('200px');
const containerOffsetTop = ref('85');

const content = ref(null)
const { toggle } = useFullscreen(content)

// 1. 创建独立的tween组
const tweenGroup = new Group()

const loadingPercentage = ref({
    percentage: '',
    completed: false
})

// Three.js 核心对象
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(65, 1, 0.1, 70000)
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

let renderer = null;
let controls = null;
let composer = null;
let css2Renderer = null;
const gltfGroup = new THREE.Group()
const css2dRendererGroup = new THREE.Group()
const boundingPlanesGroup = new THREE.Group()
let outlinePass, tilesRendererModules = [];
let modulItem = null, guandaoModule = null;
let isHideSheBei = ref(false);
let isHideGuanDao = ref(false);
// 资源管理
const resources = {
    textures: [],
    models: [],
    geometries: [],
    materials: [],
    eventListeners: [],
    animations: []
}

defineExpose([
    scene,
    camera,
    renderer,
])
// 模型配置
const gltfArray = [
    // { url: '/scyy/tuoshuichejian.glb', labelText: '脱水车间', isBbox: false },
    // { url: '/scyy/jixioufang.glb', labelText: '机修房', isBbox: false },
    // { url: '/scyy/pinghengchi.glb', labelText: '平衡池', isBbox: false },
    // { url: '/scyy/nonsuochi.glb', labelText: '浓缩池', isBbox: false },
    // { url: '/scyy/chendianchi.glb', labelText: '沉淀池', isBbox: false },
    // { url: '/scyy/jiayaojian.glb', labelText: '加药间', isBbox: false },
    // { url: '/scyy/painichi.glb', labelText: '排泥池', isBbox: false },
    // { url: '/scyy/shitan.glb', labelText: '食堂', isBbox: false },
    // { url: '/scyy/v-lvchi.glb', labelText: 'V型滤池', isBbox: false },
    // { url: '/scyy/qingshuichi.glb', labelText: '清水池', isBbox: false },
    // { url: '/scyy/guandao.glb', labelText: '', isBbox: false },
    // { url: '/scyy/gzgli.glb', labelText: '', isBbox: false },
    { url: '/modules/index.glb', labelText: '综合楼', isBbox: false },
]
const titlesPaths = [
    // '/scyy/changdi/tileset.json',
]

// 加载管理器
const loadingManager = new THREE.LoadingManager(
    () => {
        loadingPercentage.value.completed = true;
        emit('loadingFinish', scene);
        const router = new Tween(camera.position,
            tweenGroup // 关键：传入组实例
        ).to({ x: 0, y: 140, z: 110 }, 2000)
            .easing(Easing.Quartic.Out)
            .onUpdate((obj) => {
                camera.updateProjectionMatrix()
                controls?.update()
            })
            .start().onComplete(() => {
                // 设置模型的中心
                // 设置模型的中心
                tweenGroup.remove(router);
                emit('loadingFinish', scene);
                controls.minDistance = 50;  // 最小缩放距离（默认0）
                controls.maxDistance = 200; // 最大缩放距离（默认Infinity）
                controls.maxPolarAngle = Math.PI * 0.35; // 最大俯角（避免完全倒置）
            })
    },
    (url, loaded, total) => {
        loadingPercentage.value.percentage = `加载中..${((loaded / total) * 100).toFixed(2)}%`
    }
)


// 初始化场景
const initScene = async () => {

    // 初始化渲染器
    renderer = new THREE.WebGLRenderer({
        antialias: true,
        logarithmicDepthBuffer: true
    })
    updateRendererSize()
    container.value.appendChild(renderer.domElement)

    camera.position.set(0, 220, 130)
    camera.updateProjectionMatrix()

    // 初始化控制器
    controls = new OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true
    controls.minDistance = 20;  // 最小缩放距离（默认0）
    controls.maxDistance = 140; // 最大缩放距离（默认Infinity）

    // 设置场景背景
    scene.background = new THREE.Color('#02004d')

    // 初始化后期处理和标签渲染器
    initPostProcessing()
    createCSS2DRenderer()

    // 加载模型和环境
    gltfArray.forEach((item) => {
        loadModel(item)
    })

    loadEnvironment()
    titlesPaths.forEach(path => tilesRendererLoader(path))

    scene.add(gltfGroup)
    scene.add(css2dRendererGroup)
    scene.add(boundingPlanesGroup)
}
const tilesRendererLoader = (path) => {
    // 加载3D Tiles
    const tilesRenderer = new TilesRenderer(path);
    tilesRenderer.setCamera(camera);
    tilesRenderer.setResolutionFromRenderer(camera, renderer);
    tilesRenderer.group.rotation.x = -Math.PI / 2;
    scene.add(tilesRenderer.group);

    // 解码器设置
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath("https://unpkg.com/three/examples/jsm/libs/draco/gltf/");
    const loader = new GLTFLoader(tilesRenderer.manager);
    loader.setDRACOLoader(dracoLoader);
    loader.setMeshoptDecoder(MeshoptDecoder);
    tilesRenderer.manager.addHandler(/\.gltf$/, loader);

    tilesRendererModules.push(tilesRenderer);

}

// 创建标签
const createLabel = (text) => {
    const label = document.createElement("div")
    label.style.cursor = 'pointer';
    label.style.pointerEvents = 'auto';
    label.innerHTML = `
        <div class='animate__animated animate__bounceIn' style="display: flex;align-items: center;flex-direction: column;justify-content: center;">
            <div style="width:130px;height: 55px;position: relative;">
                <img src="${textBackground}" style="width:130px;height: 55px;" />
                <div class="label-text" style="position:absolute;top:12px;left:0;right:0;margin: 0 auto;text-align: center;color:#fff;font-size:18px;">${text}</div>    
            </div>
            <img src="${lineBackground}" style="width: 34px;height: 44px;margin-top: -10px;" />    
        </div>
    `
    return label
}
// 创建CSS2D渲染器
const createCSS2DRenderer = () => {
    css2Renderer = new CSS2DRenderer()
    updateCSS2DRendererSize()
    css2Renderer.domElement.style.position = 'absolute'
    css2Renderer.domElement.style.top = '0'
    css2Renderer.domElement.style.pointerEvents = 'none'
    container.value.appendChild(css2Renderer.domElement)
}

// 初始化后期处理
const initPostProcessing = () => {
    composer = new EffectComposer(renderer)

    // 添加RenderPass（带色调映射）
    const renderPass = new RenderPass(scene, camera);
    renderPass.toneMapping = renderer.toneMapping;
    renderPass.toneMappingExposure = renderer.toneMappingExposure;
    composer.addPass(renderPass);

    const fxaaPass = new ShaderPass(FXAAShader)
    const pixelRatio = renderer.getPixelRatio()
    fxaaPass.material.uniforms['resolution'].value.x = 1 / (container.value.clientWidth * pixelRatio)
    fxaaPass.material.uniforms['resolution'].value.y = 1 / (container.value.clientHeight * pixelRatio)
    composer.addPass(fxaaPass)

    const outputPass = new OutputPass();
    outputPass.toneMapping = THREE.NoToneMapping; // 避免二次处理
    outputPass.outputColorSpace = THREE.sRGBColorSpace; // r152+
    composer.addPass(outputPass);

    if (props.outlinePass) {
        // 4. 创建描边效果
        outlinePass = new OutlinePass(
            new THREE.Vector2(container.value.clientWidth, container.value.clientHeight),
            scene,
            camera
        );
        outlinePass.edgeStrength = 3.0; // 描边强度
        outlinePass.edgeGlow = 0.5;     // 边缘发光
        outlinePass.edgeThickness = 1.0; // 边缘厚度
        outlinePass.pulsePeriod = 2;    // 脉冲周期
        outlinePass.visibleEdgeColor.set('#ff0000'); // 可见边颜色
        outlinePass.hiddenEdgeColor.set('#ff0000');  // 隐藏边颜色
        composer.addPass(outlinePass);
        window.addEventListener('mousemove', onMouseMove);
    }
}


function onMouseMove(event) {
    // 获取容器相对于视口的坐标位置
    const rect = container.value.getBoundingClientRect();

    // 计算容器内的相对鼠标坐标 (考虑滚动偏移)
    const mouseX = event.clientX - rect.left;
    const mouseY = event.clientY - rect.top;

    // 转换为标准化设备坐标 (NDC: -1到1)
    mouse.x = (mouseX / rect.width) * 2 - 1;
    mouse.y = -(mouseY / rect.height) * 2 + 1;

    // 更新射线检测
    raycaster.setFromCamera(mouse, camera);

    const intersects = raycaster.intersectObjects(gltfGroup.children);


    if (intersects.length > 0) {
        // const modul = intersects[0]?.object?.parent?.parent;
        // if (!modul.resetName) return;
        // modulItem = modul;

        // css2dRendererGroup.children.forEach(item => {
        //     if (item.resetName == modul.resetName) {
        //         item.visible = true;
        //     } else {
        //         item.visible = false;
        //     }
        // })

        // outlinePass.selectedObjects = [modul];


    } else {
        outlinePass.selectedObjects = [];
        css2dRendererGroup.children.forEach(item => {
            item.visible = false;
        })
    }
}

const showModuleQiang = (value = false) => {
    gltfGroup.children.forEach(module => {
        module.traverse((item) => {
            if (['shang', 'qian', 'zuo', 'you', 'hou', 'YOU'].includes(item.name.split('_')[1])) {
                item.children.forEach(child => {
                    child.visible = value;
                });
            }
        })
    })
    isHideSheBei.value = !value;
}
const showProcess = (value = false) => {

}
const showGuanDaoMoudle = () => {
    isHideGuanDao.value = true;
    guandaoModule.traverse((child) => {
        if (child.isMesh) {
            child.material.depthWrite = true;
            child.material.depthTest = false;
            child.material.transparent = true;
        }
    })
}
const hideGuanDao = () => {
    isHideGuanDao.value = false;
    guandaoModule.traverse((child) => {
        if (child.isMesh) {
            child.material.depthWrite = true;
            child.material.depthTest = true;
            child.material.transparent = true;
        }
    })
}
// 加载环境贴图
const loadEnvironment = () => {
    const hdrLoader = new RGBELoader()
    hdrLoader.load('/golden_gate_hills_4k.hdr', (texture) => {
        texture.mapping = THREE.EquirectangularReflectionMapping
        scene.environment = texture
        resources.textures.push(texture)
    })
}
// 加载模型
const loadModel = ({ url, labelText, isBbox, sg }) => {
    const loader = new GLTFLoader(loadingManager)
    const dracoLoader = new DRACOLoader()
    dracoLoader.setDecoderPath("/draco/gltf/")
    dracoLoader.setDecoderConfig({ type: "js" })
    loader.setDRACOLoader(dracoLoader)
    loader.load(url, (gltf) => {
        const model = gltf.scene

        resources.models.push(model)

        if (url.includes('guandao')) {
            guandaoModule = model;
        }

        if (labelText) {
            const box = new THREE.Box3().setFromObject(model)
            const center = box.getCenter(new THREE.Vector3())
            const div = createLabel(labelText)

            const labelObject = new CSS2DObject(div)
            labelObject.position.set(center.x, box.max.y, center.z)
            labelObject.center.set(0.5, 1);
            labelObject.resetName = labelText
            labelObject.visible = false;
            css2dRendererGroup.add(labelObject)
            resources.models.push(labelObject)
        }

        model.resetName = labelText
        gltfGroup.add(model)
    }, (error) => {

    })
}

// 更新渲染器尺寸
const updateRendererSize = () => {
    if (!container.value) return

    const width = container.value.clientWidth
    const height = container.value.clientHeight

    camera.aspect = width / height
    camera.updateProjectionMatrix()
    renderer?.setSize(width, height)

    // 更新后期处理器
    if (composer) {
        composer.setSize(width, height)
        const passes = composer.passes
        for (let i = 0; i < passes.length; i++) {
            if (passes[i] instanceof ShaderPass && passes[i].material.uniforms['resolution']) {
                const pixelRatio = renderer.getPixelRatio()
                passes[i].material.uniforms['resolution'].value.x = 1 / (width * pixelRatio)
                passes[i].material.uniforms['resolution'].value.y = 1 / (height * pixelRatio)
            }
        }
    }
}

// 更新CSS2D渲染器尺寸
const updateCSS2DRendererSize = () => {
    if (!container.value || !css2Renderer) return
    const width = container.value.clientWidth
    const height = container.value.clientHeight
    css2Renderer.setSize(width, height)
}

// 主动画循环
const animate = () => {
    if (!container.value) return

    const rect = container.value.getBoundingClientRect()
    if (rect) {
        containerOffsetLeft.value = rect.left + 'px';
        containerOffsetTop.value = rect.top + 'px';
        renderer?.setSize(rect.width, rect.height)
        camera.aspect = rect.width / rect.height
        camera.updateProjectionMatrix()
        css2Renderer?.setSize(rect.width, rect.height)
        css2Renderer?.render(scene, camera)
    }

    composer?.render()
    controls?.update();
    requestAnimationFrame(animate)

    tilesRendererModules.forEach(tiles => tiles.update());

    // 更新 Tween 动画
    tweenGroup.update();
}

// 窗口大小变化处理
const handleResize = () => {
    updateRendererSize()
    updateCSS2DRendererSize()
}
// 组件挂载
onMounted(() => {

    initScene()
    animate()

    window.addEventListener('resize', handleResize)
    document.onmousedown = () => {
        let modul = outlinePass?.selectedObjects[0];
        if (modul) {
            modulItem = modul;
            isHideSheBei.value = true;
            modul.traverse((item) => {
                if (['shang', 'qian', 'zuo', 'you', 'hou', 'YOU'].includes(item.name.split('_')[1])) {
                    item.children.forEach(child => {
                        child.visible = false;
                    });
                }
            })
        }
    }
})

// 组件卸载前清理
onBeforeUnmount(() => {
    // 移除事件监听
    window.removeEventListener('resize', handleResize)
    window.removeEventListener('mousemove', onMouseMove);

    // 清理动画
    resources.animations.forEach(anim => anim.kill())

    // 清理事件监听器
    resources.eventListeners.forEach(({ element, handler }) => {
        element?.removeEventListener('click', handler)
    })

    // 清理场景
    scene.traverse(object => {
        if (!object.isMesh) return

        if (object.geometry) {
            object.geometry.dispose()
        }

        if (object.material) {
            if (Array.isArray(object.material)) {
                object.material.forEach(m => m.dispose())
            } else {
                object.material.dispose()
            }
        }
    })
    // 清理纹理
    resources.textures.forEach(texture => {
        texture.dispose()
        texture.image?.close?.()
    })

    // 清理渲染器
    if (renderer) {
        container.value?.removeChild(renderer.domElement)
        renderer.dispose()
    }

    // 清理CSS2D渲染器
    if (css2Renderer) {
        container.value?.removeChild(css2Renderer.domElement)
    }

    // 清理控制器
    controls?.dispose();

    // 清理GSAP
    gsap.globalTimeline.clear();

    tweenGroup.removeAll();

})
</script>

<style scoped lang="scss">
.three-container {
    width: 100vw;
    height: 100vh;
    position: relative;
    overflow: hidden;
}

.content {
    width: 100%;
    height: 100%;
    position: relative;
}

:deep(.center-bottom-content) {
    width: 30%;
}

.button-list {
    display: flex;
    justify-content: center;
    width: 100%;

    .button {
        position: relative;
        width: 132px;
        height: 60px;
        text-align: center;
        line-height: 50px;
        cursor: pointer;
        margin: 0 20px;

        >img {
            position: absolute;
            z-index: -1;
            left: 0;
            width: 132px;
            height: 60px;
        }

        .label {
            width: 132px;
            font-size: 16px;
            text-align: center;
            color: #66FFFF;
        }
    }
}
</style>